<template>
    <div>
        <form-above-file-table
                v-show="!previewMode"
                :value-key="searchKey"
                :query-search="querySearch"
                :title="title"
                @upload-clicked="upload"
                @mkdir-clicked="mkdir"
                @search-clicked="search"
        >
            <slot name="form"></slot>
        </form-above-file-table>
        <base-file-list
                v-show="!previewMode"
                ref="table"
                :load-page="loadPage"
                :load-root-meta="loadRootMeta"
                :current-dir.sync="currentDir"
                @preview="preview"
                @download-file="downloadFile"
                @change-file-meta="changeFileMeta"
                @delete="onDelete"
        >
            <slot name="columns"></slot>
        </base-file-list>
        <!-- 预览模块 -->
        <previewer :visible.sync="previewMode"
                   ref="previewer"
                   @unsupported="previewUnsupported"
                   @loading = "previewLoading"
        ></previewer>
    </div>
</template>

<script>
    import BaseFileList from "~/components/file-list/BaseFileList";
    import FormAboveFileTable from "~/components/file-list/FormAboveFileTable";
    import {getEnterpriseDetails} from "~/interface/info/EnterpriseInfo";
    import {CACHE_EXPIRE_TIME} from "~/Contants";
    import Previewer from "~/components/file-list/Previewer";

    /**
     * 此组件完成了搜索、缓存、文件预览等功能。
     */
    export default {
        name: "LicenceFileList",
        components: {FormAboveFileTable, BaseFileList, Previewer},
        props:{
            title:{
                type:String,
                default: "资源",
            },
            // 应用搜索的关键字。
            searchKey:{
                type:String,
                default: "name",
            },
            rootMetaUrl:{
                type:String,
                require: true,
            },
            listDirectoryUrl:{
                type: String,
                require: true,
            },
            downloadUrl:{
                type:String,
                default:"/file/download"
            },
            deleteUrl:{
                type:String,
                default:"/file/rm"
            },
            loadFileMetaUrl:{
                type:String,
                default:"/file"
            },
            filter:{
                type:Function,
                default: (_v)=>true,
            },
            mapper:{
                type:Function,
                default: (v)=>v,
            },
            sortBy:{
                type:Function,
            },
        },
        data(){
            return{
                queryString:"",
                currentDir:{
                    id:-1,
                    length:0,
                    searchMark: false,
                },
                cache:{},
                previewMode: false,
            };
        },
        methods:{
            async loadPage(pageMeta, pageSize, resetCache){
                if(this.currentDir.id!==pageMeta.id){
                    console.warn(`证照当前目录与pageMeta不符！currentDir.id:${this.currentDir.id},pageMeta.id:${pageMeta.id}`);
                }
                const page = pageMeta.page;
                const children = await this.getChildren(this.currentDir,resetCache);
                return children.slice((page-1)*pageSize,page*pageSize);
            },
            async getChildren(dir,resetCache){
                dir = dir || this.currentDir;
                if(dir.searchMark) return dir.children||[];
                if(
                    resetCache||                // 如果强制刷新缓存
                    !this.cache[dir.id]||       // 如果未缓存此数据
                    this.isCacheTimeOut(dir)    // 如果缓存已过期
                ){
                    this.resetCache(dir);       // 清除此文件夹的缓存
                    await this.loadDirToCache(dir); // 获取数据
                }
                console.log("getChildren 缓存状态：",this.cache);
                return this.cache[dir.id].children;
            },
            /**
             * 加载此文件夹的内容至cache。
             */
            async loadDirToCache(dir){
                this.resetCache(dir);           // 清除此文件夹的缓存
                try {
                    const response = await this.$http.get(this.listDirectoryUrl,
                        {params:{id:dir.id}});              // 发起无缓存请求，获取文件夹资源。
                    const children = this.postChildrenLoaded(response.data.parameter.array);
                    this.cache[dir.id] = {                          // 缓存获取的数据
                        meta: dir,
                        cacheTime: Date.now(),
                        children,
                    };
                    dir.length = children.length;
                }catch (e) {
                    console.log(e);
                    let err = e;
                    if(err.response&&err.response.hasOwnProperty("data"))err = err.response.data;
                    throw err.message;
                }
            },
            async loadFileMeta(id){
                try {
                    const response = await this.$http.get(`${this.loadFileMetaUrl}/${id}`);
                    return response.data.parameter;
                }catch (e) {
                    let err = e;
                    if(err.response&&err.response.hasOwnProperty("data"))err = err.response.data;
                    throw e;
                }
            },
            /**
             * 对于children数据的处理。
             */
            postChildrenLoaded(children){
                if(!children) return [];
                const ans = children.filter(this.filter).map(this.mapper);
                if(this.sortBy) ans.sort(this.sortBy);
                return ans;
            },
            resetCache(dir){
                if(!dir) {
                    console.warn("已清空证照文件列表缓存。");
                    this.cache = {};
                    return undefined;
                }
                if(this.cache[dir.id]) delete this.cache[dir.id];
            },
            isCacheTimeOut(dir){
                const target = this.cache[dir.id];
                if(!target) return true;
                return Date.now() - target.cacheTime > CACHE_EXPIRE_TIME;
            },
            async loadRootMeta(){
                try{
                    const unitId = (await getEnterpriseDetails()).id;
                    const response = await this.$http.get(
                        this.rootMetaUrl,{params:{unitId:unitId}});
                    return response.data.parameter;
                }catch (e) {
                    console.log(e);
                    let err = e;
                    if(err.response&&err.response.hasOwnProperty("data"))err = err.response.data;
                    throw new Error(err.message);
                }
            },
            buildSearchExp(queryString){
                queryString = queryString.trim().replace(/\s+/g," ");
                return new RegExp(queryString.replace(" ",".*"));
            },
            async querySearch(queryString,cb){
                if(typeof queryString !== "string") {
                    cb([]);
                    return undefined;
                }
                queryString = queryString.trim().replace(/\s+/g," ");
                if(queryString.trim().length===0){
                    cb([]);
                    return undefined;
                }
                const exp = new RegExp(queryString.replace(" ",".*"));
                const children = await this.getChildren(this.currentDir);
                if(!children) {
                    cb([]);
                    return undefined;
                }
                cb(children.filter(v=>{
                    if(!v) return false;
                    const key = v[this.searchKey];
                    return exp.test(key);
                }).slice(0,5));
            },
            async search(queryString){
                if(!queryString|| !queryString.trim()) return undefined;
                const exp = this.buildSearchExp(queryString);
                const children = await this.getChildren(this.currentDir);
                if(!children) return undefined;
                const ansArr = children.filter(v=>exp.test(v[this.searchKey]));
                const searchDir = {
                    id: -1,
                    name: `搜索'${queryString}'的结果`,
                    searchMark: true,
                    children: ansArr,
                    length: ansArr.length,
                };
                this.$refs.table.$emit("open-dir",searchDir,true);
            },
            mkdir(){
                this.$emit('mkdir-clicked',this.currentDir);
            },
            upload(){
                this.$emit('upload-clicked',this.currentDir);
            },
            previewSource(file){
                const extName = file.ext?'.'+file.ext:'';
                return `${this.$http.defaults.baseURL}${this.downloadUrl}/${file.id}${extName}`;
            },
            async preview(file){
                if(!file||file["isDir"]===true)return undefined;
                let src = null;
                try{
                    src = this.previewSource(file);
                }catch (e) {
                    this.$alert(e.message,'预览失败',{type:'error'});
                    return undefined;
                }
                if(!src){
                    this.$alert("无法索引到文件资源的位置。",'预览失败',{type:'error'});
                    return undefined;
                }
                this.$refs.previewer.$emit("reload",file.name,file.ext,src,file.id);
            },
            previewUnsupported(){
                this.$alert("无法预览此文件。",'无法预览',{type:'error'});
            },
            previewLoading(){
                this.previewMode = true;
            },
            async deleteFile(file){
                try{
                    await this.$http.delete(`${this.deleteUrl}/${file.id}`);
                }catch (e) {
                    console.log(e);
                    let err = e;
                    if(err.response&&err.response.hasOwnProperty("data"))err = err.response.data;
                    throw e;
                }
            },
            async onDelete(file){
                try{
                    await this.$confirm(`此操作将删除${file.name}, 是否继续?`, '提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    })
                }catch (e) {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                    return undefined;
                }
                try{
                    await this.deleteFile(file);
                    this.resetCache(this.currentDir);
                    this.$refs.table.$emit("reload");
                    this.$message({
                        type: 'success',
                        message: '删除成功!'
                    });
                }catch (e) {
                    this.$notify.error({
                        title: `删除${file.name}失败。`,
                        message: e.message
                    });
                }
            },downloadFile(file){
                const extName = file.ext?'.'+file.ext:'';
                window.open(`${this.$http.defaults.baseURL}${this.downloadUrl}/${file.id}${extName}`)
            },
            changeFileMeta(file){
                if(file&&file.isDir){
                    this.$emit("change-dir-meta",this.currentDir,file)
                }else{
                    this.$emit('change-file-meta',this.currentDir,file)
                }
            }
        },
        mounted() {
            this.$on("reload-dir",(dir)=>{
                this.resetCache(dir);
                if(dir&&this.currentDir.id===dir.id){
                    this.$refs.table.$emit("reload");
                }
            });
        }
    }
</script>

<style scoped>

</style>
